"""
投票协调器模块

实现基于投票的协调策略，用于处理多个智能体产生冲突结果的情况
"""

import asyncio
import statistics
import time
from collections import Counter
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple

from agents.base_agent import BaseAgent
from schema import Task, TaskStatus, Result
from .base_coordinator import BaseCoordinator


@dataclass
class Vote:
    """投票"""
    agent_id: str
    agent_name: str
    choice: str
    confidence: float
    reasoning: str
    timestamp: datetime = field(default_factory=datetime.now)


@dataclass
class VotingResult:
    """投票结果"""
    winning_choice: str
    vote_count: int
    total_votes: int
    confidence_score: float
    consensus_level: float
    votes: List[Vote]
    tie_breaking_method: Optional[str] = None


class VotingCoordinator(BaseCoordinator):
    """
    投票协调器
    
    通过投票机制解决多个智能体之间的冲突，适用于需要达成共识的场景
    """
    
    def __init__(self, coordinator_id: str, name: str, 
                 min_consensus: float = 0.6, timeout: int = 300,
                 tie_breaking_method: str = "confidence"):
        """
        初始化投票协调器
        
        Args:
            coordinator_id: 协调器ID
            name: 协调器名称
            min_consensus: 最小共识阈值 (0-1)
            timeout: 超时时间（秒）
            tie_breaking_method: 平局处理方法 ("confidence", "random", "first")
        """
        super().__init__(coordinator_id, name)
        
        self.min_consensus = min_consensus
        self.timeout = timeout
        self.tie_breaking_method = tie_breaking_method
        self._voting_history: List[Dict[str, Any]] = []
        self._active_votes: Dict[str, List[Vote]] = {}
    
    async def coordinate(self, task: Task) -> Result:
        """
        协调执行任务
        
        Args:
            task: 要执行的任务
            
        Returns:
            执行结果
        """
        start_time = time.time()
        
        try:
            # 更新任务状态
            task.update_status(TaskStatus.IN_PROGRESS)
            
            # 检查是否有可用的智能体
            if not self.agents:
                return Result(
                    status=TaskStatus.FAILED,
                    data=None,
                    error_message="没有可用的智能体",
                    metadata={
                        "coordinator_id": self.coordinator_id,
                        "execution_time": time.time() - start_time
                    }
                )
            
            # 执行投票流程
            voting_result = await self._conduct_voting(task)
            
            # 根据投票结果执行最终决策
            final_result = await self._execute_decision(task, voting_result)
            
            # 记录投票历史
            self._record_voting(task, voting_result, final_result, time.time() - start_time)
            
            return final_result
            
        except Exception as e:
            error_result = Result(
                status=TaskStatus.FAILED,
                data=None,
                error_message=f"投票协调执行失败: {str(e)}",
                metadata={
                    "coordinator_id": self.coordinator_id,
                    "execution_time": time.time() - start_time
                }
            )
            
            self._record_voting(task, None, error_result, time.time() - start_time)
            return error_result
    
    async def _conduct_voting(self, task: Task) -> VotingResult:
        """
        执行投票流程
        
        Args:
            task: 要投票的任务
            
        Returns:
            投票结果
        """
        # 并行执行所有智能体获取投票
        voting_tasks = []
        for agent_id, (agent, role) in self.agents.items():
            voting_task = self._get_agent_vote(agent, task, agent_id, role)
            voting_tasks.append(voting_task)
        
        # 等待所有投票完成
        votes = await asyncio.gather(*voting_tasks, return_exceptions=True)
        
        # 处理异常投票
        valid_votes = []
        for i, vote in enumerate(votes):
            if isinstance(vote, Exception):
                # 创建默认投票
                agent_id = list(self.agents.keys())[i]
                agent, role = self.agents[agent_id]
                default_vote = Vote(
                    agent_id=agent_id,
                    agent_name=agent.name,
                    choice="abstain",
                    confidence=0.0,
                    reasoning=f"投票失败: {str(vote)}"
                )
                valid_votes.append(default_vote)
            else:
                valid_votes.append(vote)
        
        # 统计投票结果
        return self._count_votes(valid_votes)
    
    async def _get_agent_vote(self, agent: BaseAgent, task: Task,
                            agent_id: str, role: str) -> Vote:
        """
        获取智能体的投票
        
        Args:
            agent: 智能体
            task: 任务
            agent_id: 智能体ID
            role: 角色
            
        Returns:
            投票对象
        """
        try:
            # 创建投票任务
            voting_task = Task(
                id=f"vote_{task.id}_{agent_id}",
                title=f"投票任务: {task.title}",
                description=f"请对以下任务进行投票决策：\n{task.description}\n\n请提供你的选择、置信度和理由。",
                priority=task.priority
            )
            
            # 执行智能体
            result = await asyncio.wait_for(
                agent.act(voting_task),
                timeout=self.timeout
            )
            
            # 解析投票结果
            vote_data = self._parse_vote_result(result, agent_id, agent.name)
            return vote_data
            
        except asyncio.TimeoutError:
            return Vote(
                agent_id=agent_id,
                agent_name=agent.name,
                choice="timeout",
                confidence=0.0,
                reasoning="投票超时"
            )
        except Exception as e:
            return Vote(
                agent_id=agent_id,
                agent_name=agent.name,
                choice="error",
                confidence=0.0,
                reasoning=f"投票错误: {str(e)}"
            )
    
    def _parse_vote_result(self, result: Result, agent_id: str, agent_name: str) -> Vote:
        """
        解析投票结果
        
        Args:
            result: 智能体执行结果
            agent_id: 智能体ID
            agent_name: 智能体名称
            
        Returns:
            投票对象
        """
        if not result.success:
            return Vote(
                agent_id=agent_id,
                agent_name=agent_name,
                choice="error",
                confidence=0.0,
                reasoning=f"执行失败: {result.error_message}"
            )
        
        # 尝试从结果中提取投票信息
        data = result.data
        if isinstance(data, str):
            # 简单解析文本结果
            choice, confidence, reasoning = self._parse_text_vote(data)
        elif isinstance(data, dict):
            # 解析结构化结果
            choice = data.get("choice", "unknown")
            confidence = float(data.get("confidence", 0.5))
            reasoning = data.get("reasoning", "无理由")
        else:
            # 默认投票
            choice = "unknown"
            confidence = 0.5
            reasoning = "无法解析投票结果"
        
        return Vote(
            agent_id=agent_id,
            agent_name=agent_name,
            choice=str(choice),
            confidence=max(0.0, min(1.0, confidence)),
            reasoning=str(reasoning)
        )
    
    def _parse_text_vote(self, text: str) -> Tuple[str, float, str]:
        """
        从文本中解析投票信息
        
        Args:
            text: 文本内容
            
        Returns:
            (选择, 置信度, 理由)
        """
        text_lower = text.lower()
        
        # 简单的关键词匹配
        if "同意" in text_lower or "支持" in text_lower or "yes" in text_lower:
            choice = "yes"
        elif "不同意" in text_lower or "反对" in text_lower or "no" in text_lower:
            choice = "no"
        elif "弃权" in text_lower or "abstain" in text_lower:
            choice = "abstain"
        else:
            choice = "unknown"
        
        # 尝试提取置信度
        confidence = 0.5
        if "高" in text_lower or "high" in text_lower:
            confidence = 0.8
        elif "低" in text_lower or "low" in text_lower:
            confidence = 0.3
        elif "中" in text_lower or "medium" in text_lower:
            confidence = 0.5
        
        return choice, confidence, text
    
    def _count_votes(self, votes: List[Vote]) -> VotingResult:
        """
        统计投票结果
        
        Args:
            votes: 投票列表
            
        Returns:
            投票结果
        """
        if not votes:
            return VotingResult(
                winning_choice="no_votes",
                vote_count=0,
                total_votes=0,
                confidence_score=0.0,
                consensus_level=0.0,
                votes=votes
            )
        
        # 统计选择
        choice_counts = Counter(vote.choice for vote in votes)
        total_votes = len(votes)
        
        # 找到得票最多的选择
        winning_choice, vote_count = choice_counts.most_common(1)[0]
        
        # 计算共识水平
        consensus_level = vote_count / total_votes
        
        # 计算置信度分数
        winning_votes = [vote for vote in votes if vote.choice == winning_choice]
        confidence_score = statistics.mean([vote.confidence for vote in winning_votes]) if winning_votes else 0.0
        
        # 处理平局
        tie_breaking_method = None
        if consensus_level < self.min_consensus:
            # 需要平局处理
            top_choices = [choice for choice, count in choice_counts.most_common(2)]
            if len(top_choices) > 1 and choice_counts[top_choices[0]] == choice_counts[top_choices[1]]:
                # 平局，使用平局处理方法
                winning_choice, tie_breaking_method = self._resolve_tie(votes, top_choices)
                vote_count = choice_counts[winning_choice]
                consensus_level = vote_count / total_votes
        
        return VotingResult(
            winning_choice=winning_choice,
            vote_count=vote_count,
            total_votes=total_votes,
            confidence_score=confidence_score,
            consensus_level=consensus_level,
            votes=votes,
            tie_breaking_method=tie_breaking_method
        )
    
    def _resolve_tie(self, votes: List[Vote], top_choices: List[str]) -> Tuple[str, str]:
        """
        解决平局
        
        Args:
            votes: 投票列表
            top_choices: 得票最多的选择
            
        Returns:
            (获胜选择, 处理方法)
        """
        if self.tie_breaking_method == "confidence":
            # 基于置信度解决平局
            choice_confidences = {}
            for choice in top_choices:
                choice_votes = [vote for vote in votes if vote.choice == choice]
                avg_confidence = statistics.mean([vote.confidence for vote in choice_votes])
                choice_confidences[choice] = avg_confidence
            
            winning_choice = max(choice_confidences, key=choice_confidences.get)
            return winning_choice, "confidence"
        
        elif self.tie_breaking_method == "random":
            # 随机选择
            import random
            winning_choice = random.choice(top_choices)
            return winning_choice, "random"
        
        else:  # "first"
            # 选择第一个
            winning_choice = top_choices[0]
            return winning_choice, "first"
    
    async def _execute_decision(self, task: Task, voting_result: VotingResult) -> Result:
        """
        执行最终决策
        
        Args:
            task: 原始任务
            voting_result: 投票结果
            
        Returns:
            执行结果
        """
        # 检查是否达到共识
        if voting_result.consensus_level < self.min_consensus:
            return Result(
                status=TaskStatus.FAILED,
                data={
                    "voting_result": voting_result,
                    "consensus_required": self.min_consensus,
                    "consensus_achieved": voting_result.consensus_level
                },
                error_message=f"未达到最小共识要求: {voting_result.consensus_level:.2f} < {self.min_consensus}",
                metadata={
                    "coordinator_type": "voting",
                    "coordinator_id": self.coordinator_id,
                    "voting_method": "consensus"
                }
            )
        
        # 根据投票结果执行任务
        if voting_result.winning_choice in ["yes", "同意", "支持"]:
            # 执行任务
            return await self._execute_task_with_consensus(task, voting_result)
        elif voting_result.winning_choice in ["no", "不同意", "反对"]:
            # 拒绝执行
            return Result(
                status=TaskStatus.CANCELLED,
                data={
                    "voting_result": voting_result,
                    "decision": "rejected"
                },
                error_message="任务被投票拒绝",
                metadata={
                    "coordinator_type": "voting",
                    "coordinator_id": self.coordinator_id,
                    "voting_method": "consensus"
                }
            )
        else:
            # 其他情况
            return Result(
                status=TaskStatus.FAILED,
                data={
                    "voting_result": voting_result,
                    "decision": "unknown"
                },
                error_message=f"未知的投票结果: {voting_result.winning_choice}",
                metadata={
                    "coordinator_type": "voting",
                    "coordinator_id": self.coordinator_id,
                    "voting_method": "consensus"
                }
            )
    
    async def _execute_task_with_consensus(self, task: Task, voting_result: VotingResult) -> Result:
        """
        在达成共识后执行任务
        
        Args:
            task: 任务
            voting_result: 投票结果
            
        Returns:
            执行结果
        """
        # 选择支持该决策的智能体执行任务
        supporting_agents = [
            vote for vote in voting_result.votes 
            if vote.choice == voting_result.winning_choice
        ]
        
        if not supporting_agents:
            return Result(
                status=TaskStatus.FAILED,
                data={"voting_result": voting_result},
                error_message="没有支持该决策的智能体",
                metadata={
                    "coordinator_type": "voting",
                    "coordinator_id": self.coordinator_id
                }
            )
        
        # 选择置信度最高的智能体执行任务
        best_agent_vote = max(supporting_agents, key=lambda v: v.confidence)
        agent_id = best_agent_vote.agent_id
        
        if agent_id not in self.agents:
            return Result(
                status=TaskStatus.FAILED,
                data={"voting_result": voting_result},
                error_message=f"智能体 {agent_id} 不存在",
                metadata={
                    "coordinator_type": "voting",
                    "coordinator_id": self.coordinator_id
                }
            )
        
        # 执行任务
        agent, role = self.agents[agent_id]
        try:
            result = await asyncio.wait_for(
                agent.act(task),
                timeout=self.timeout
            )
            
            # 添加投票信息到结果
            result.metadata = result.metadata or {}
            result.metadata.update({
                "voting_result": {
                    "winning_choice": voting_result.winning_choice,
                    "consensus_level": voting_result.consensus_level,
                    "confidence_score": voting_result.confidence_score,
                    "executing_agent": agent_id,
                    "executing_agent_confidence": best_agent_vote.confidence
                }
            })
            
            return result
            
        except Exception as e:
            return Result(
                status=TaskStatus.FAILED,
                data={"voting_result": voting_result},
                error_message=f"任务执行失败: {str(e)}",
                metadata={
                    "coordinator_type": "voting",
                    "coordinator_id": self.coordinator_id
                }
            )
    
    def _record_voting(self, task: Task, voting_result: Optional[VotingResult],
                      final_result: Result, total_time: float) -> None:
        """
        记录投票历史
        
        Args:
            task: 任务
            voting_result: 投票结果
            final_result: 最终结果
            total_time: 总执行时间
        """
        voting_record = {
            "timestamp": datetime.now().isoformat(),
            "task_id": task.id,
            "task_title": task.title,
            "total_time": total_time,
            "agent_count": len(self.agents),
            "voting_result": voting_result.__dict__ if voting_result else None,
            "final_status": final_result.status.value,
            "consensus_achieved": voting_result.consensus_level if voting_result else 0.0
        }
        
        self._voting_history.append(voting_record)
        
        # 限制历史记录数量
        if len(self._voting_history) > 100:
            self._voting_history = self._voting_history[-100:]
    
    def get_voting_history(self, limit: int = 10) -> List[Dict[str, Any]]:
        """
        获取投票历史
        
        Args:
            limit: 限制数量
            
        Returns:
            投票历史列表
        """
        return self._voting_history[-limit:]
    
    def get_consensus_stats(self) -> Dict[str, Any]:
        """
        获取共识统计信息
        
        Returns:
            共识统计信息
        """
        if not self._voting_history:
            return {
                "total_votings": 0,
                "consensus_rate": 0.0,
                "average_consensus_level": 0.0,
                "average_confidence": 0.0
            }
        
        total_votings = len(self._voting_history)
        consensus_achieved = len([h for h in self._voting_history 
                                if h["consensus_achieved"] >= self.min_consensus])
        consensus_rate = consensus_achieved / total_votings if total_votings > 0 else 0.0
        
        total_consensus = sum(h["consensus_achieved"] for h in self._voting_history)
        average_consensus_level = total_consensus / total_votings if total_votings > 0 else 0.0
        
        # 计算平均置信度
        total_confidence = 0.0
        confidence_count = 0
        for h in self._voting_history:
            if h["voting_result"] and "confidence_score" in h["voting_result"]:
                total_confidence += h["voting_result"]["confidence_score"]
                confidence_count += 1
        
        average_confidence = total_confidence / confidence_count if confidence_count > 0 else 0.0
        
        return {
            "total_votings": total_votings,
            "consensus_rate": consensus_rate,
            "average_consensus_level": average_consensus_level,
            "average_confidence": average_confidence,
            "min_consensus_threshold": self.min_consensus,
            "tie_breaking_method": self.tie_breaking_method
        }
    
    def get_status(self) -> Dict[str, Any]:
        """
        获取协调器状态
        
        Returns:
            状态信息
        """
        base_status = super().get_status()
        base_status.update({
            "coordinator_type": "voting",
            "min_consensus": self.min_consensus,
            "timeout": self.timeout,
            "tie_breaking_method": self.tie_breaking_method,
            "voting_history_count": len(self._voting_history),
            "consensus_stats": self.get_consensus_stats()
        })
        
        return base_status
    
    def set_min_consensus(self, min_consensus: float) -> None:
        """
        设置最小共识阈值
        
        Args:
            min_consensus: 最小共识阈值 (0-1)
        """
        self.min_consensus = max(0.0, min(1.0, min_consensus))
    
    def set_tie_breaking_method(self, method: str) -> None:
        """
        设置平局处理方法
        
        Args:
            method: 平局处理方法 ("confidence", "random", "first")
        """
        if method in ["confidence", "random", "first"]:
            self.tie_breaking_method = method
    
    def clear_voting_history(self) -> None:
        """清空投票历史"""
        self._voting_history.clear()
    
    def __str__(self) -> str:
        return f"VotingCoordinator(id='{self.coordinator_id}', agents={len(self.agents)}, min_consensus={self.min_consensus})"
    
    def __repr__(self) -> str:
        return f"<VotingCoordinator(id='{self.coordinator_id}', name='{self.name}', agents={len(self.agents)})>"
